﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#define _DEBUG
#ifdef _DEBUG
#pragma comment (lib, "weye_lib_Debug_v142_x86")
#else
#pragma comment (lib, "weye_lib_Release_v142_x86")
#endif

#pragma execution_character_set("utf-8")
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), threshold(4.0f)
    , ui(new Ui::MainWindow)
    , serialbus(std::make_shared<EventBus>())
    , ProtocolManager_(std::make_shared<ProtocolManager>())
    , ProtocolHandler_(std::make_shared<SelfProtocolHandler>(serialbus))
    , SerialPort_(std::make_shared<SerialPort>(this, serialbus))
    //, chartView(new ChartView(&chart, this))
{
    ui->setupUi(this);

    ProtocolManager_->addHandler(ProtocolHandler_);
    SerialPort_->setProtocolManager(ProtocolManager_);
    setupUIControls();
    setupChartVisualization();
    callback_register();
}

MainWindow::~MainWindow()
{
    if (data_generate_thread.joinable())
    {
        data_generate_thread.join();
    }

    if (data_store_thread.joinable())
    {
        data_store_thread.join();
    }

    if (obj_store_thread.joinable())
    {
        obj_store_thread.join();
    }

    delete ui;
}

void MainWindow::setupUIControls()
{
    setupSerialPortUI();
    setupLogFolders();

    model = new QStandardItemModel(0, 2, ui->tableView); // 0 行，2 列

    model->setHeaderData(0, Qt::Horizontal, "序号");
    model->setHeaderData(1, Qt::Horizontal, "速度 (m/s)");

    // 将模型设置给 QTableView
    ui->tableView->setModel(model);
}

void MainWindow::setupChartVisualization()
{
    fft_mag_data = std::make_shared<std::vector<uint16_t>>(4096);

    chart.addSeries(&FFTSeries);
    chart.addSeries(&ThresholdSeries);
    chart.createDefaultAxes();

    QValueAxis* m_axisX = (QValueAxis*)chart.axes(Qt::Horizontal, &FFTSeries).at(0);//获取图表中的横坐标轴
    QValueAxis* m_axisY = (QValueAxis*)chart.axes(Qt::Vertical, &FFTSeries).at(0);  //获取图表中的纵坐标轴
    m_axisX->setGridLineVisible(true);                                           //设置网格线可见
    m_axisX->setRange(-21, 21);                                              //设置坐标轴范围
    m_axisX->setTickCount(10);
    m_axisX->setTitleText("距离");
    m_axisY->setRange(0, 100);
    m_axisY->setGridLineVisible(true);
    m_axisY->setTickCount(10);
    m_axisY->setTitleText("能量");

    chartView = new ChartView(&chart, this);
    chartView->setRenderHint(QPainter::Antialiasing); // 可选的渲染选项
    //chartView->setRubberBand(QChartView::HorizontalRubberBand);
    chartView->setViewport(new QOpenGLWidget); // 使用 OpenGL 加速
    //chartView->setChart(&chart);
    ui->gridLayout_4->addWidget(chartView);

    chartView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    ui->gridLayout_4->setRowStretch(0, 1);  // 设置布局行伸缩权重
}

void MainWindow::setupLogFolders()
{
    basefolder = QApplication::applicationDirPath() + QDir::separator() + "log";
    create_time = QDateTime::currentDateTime().toString("MM-dd@hh_mm_ss");
    timeStampedFolder = basefolder + QDir::separator() + create_time;

    QDir baseDir(basefolder);
    if (baseDir.mkpath(".")) {
        qDebug() << "Base folder created successfully!";
    }
    else {
        qDebug() << "Base folder already exists.";
    }

    QDir timeStampedDir(timeStampedFolder);
    if (timeStampedDir.mkpath(".")) {
        qDebug() << "Time-stamped folder created successfully!";
    }
    else {
        qDebug() << "Time-stamped folder already exists.";
    }

    QStringList subfolders = { "speed", "range" };
    for (const QString& subfolder : subfolders) {
        QString subfolderPath = timeStampedFolder + QDir::separator() + subfolder;
        QDir subfolderDir(subfolderPath);
        if (subfolderDir.mkpath(".")) {
            qDebug() << subfolder << "folder created successfully!";
        }
        else {
            qDebug() << subfolder << "folder already exists.";
        }
    }
}

void MainWindow::setupSerialPortUI()
{

    auto port_name = scanAvailableSerialPorts();
    ui->comselect->clear();

    if (port_name.isEmpty()) {
        ui->comselect->addItem("无可用串口");
        ui->combutton->setDisabled(true);
    }
    else {
        ui->comselect->addItems(port_name);
        ui->combutton->setDisabled(false);
    }

    // 添加波特率选项
    QList<QString> baudrate_list;
    baudrate_list << "921600" << "115200" << "57600" << "9600";
    ui->baudselect->clear();
    ui->baudselect->addItems(baudrate_list);
}

QStringList MainWindow::scanAvailableSerialPorts()
{
    QStringList port_info;

    foreach(const QSerialPortInfo & info, QSerialPortInfo::availablePorts())
    {
        port_info << info.portName();
    }
    return port_info;
}

void MainWindow::alg_init()
{
    if (protocol::DeviceAddress::LIQUID) 
    {
        tracker1D_init(liquidSpeedRes);
    }
    else if(protocol::DeviceAddress::OBJECT)
    {
        tracker1D_init(objectDistRes);
    }
}


void MainWindow::callback_register()
{
    connect(ui->refreshbutton,SIGNAL(clicked()),this,SLOT(refreshSerialPort()));//complete
    connect(ui->combutton,SIGNAL(clicked()),this,SLOT(controlSerialPort()));//complete
    connect(SerialPort_.get(), &SerialPort::dataReceived, this, &MainWindow::receiveRadarData);

    connect(ui->data_check, SIGNAL(stateChanged(int)), this, SLOT(data_check_datachanged(int)));
    connect(ui->rawdata_check, &QCheckBox::stateChanged, this, &MainWindow::rawdata_store_param_config);

    connect(ui->lineEdit, &QLineEdit::textChanged, this, [&] {
        float tmp = ui->lineEdit->text().toFloat();
        if (tmp <= 128.0f && tmp >= 1.0f)
        {
            threshold = tmp;
        }
        else
        {
            ui->lineEdit->setText(QString("%1").arg(threshold));
        }
        });
    //connect(this, &MainWindow::resized, this, &MainWindow::adjustGridLayoutSize);

    data_generate_thread = std::thread(&MainWindow::processRadarDataTask, this);
    data_store_thread = std::thread(&MainWindow::data_store_task, this);
    obj_store_thread = std::thread(&MainWindow::obj_store_task, this);

    connect(&QChartRefreshTimer,SIGNAL(timeout()),this,SLOT(updateChart()));

    QChartRefreshTimer.start(10);
}

void MainWindow::controlSerialPort()
{
    if (!SerialPort_) {
        QMessageBox::warning(this, "ERROR", "Serial port instance not initialized");
        return;
    }

    if (!SerialPort_->isOpen()) {
        const QString port = ui->comselect->currentText();
        if (port.isEmpty()) 
        {
            QMessageBox::warning(this, "ERROR", "No serial port selected");
            return;
        }

        bool ok = false;
        const int baudrate = ui->baudselect->currentText().toInt(&ok);
        if (!ok || baudrate <= 0) {
            QMessageBox::warning(this, "ERROR", "Invalid baudrate value");
            return;
        }

        if (!SerialPort_->open(port, baudrate)) {
            QMessageBox::warning(this, "ERROR",
                "Failed to open serial port:\n" + SerialPort_->errorString());
            return;
        }

        // 成功打开后的 UI 更新
        ui->combutton->setText(tr("关闭串口"));
        ui->comselect->setEnabled(false);
        ui->baudselect->setEnabled(false);
    }
    else {
        SerialPort_->close();

        // 关闭后的 UI 更新
        ui->combutton->setText(tr("打开串口"));
        ui->comselect->setEnabled(true);
        ui->baudselect->setEnabled(true);
    }
}

void MainWindow::updateChart()
{
    QFont font("Arial", 16);
    ResultText.setFont(font);
    QString str;

    if (!point_data.empty() && !threshold_data.empty())
    {
        std::unique_lock<std::mutex> lock(mtx);
        QList<QPointF> temp = point_data.front();
        point_data.pop();
        QList<QPointF> temp1 = threshold_data.front();
        threshold_data.pop();

        FFTSeries.replace(temp);
        ThresholdSeries.replace(temp1);

    }

    if (!SpeedQueue.empty())
    {
        SpeedConfiguration speedconfig;
        if (SpeedQueue.try_dequeue(speedconfig))
        {
            for (auto &temp : speedconfig.profiles)
            {
                str += QString("s:") + QString::asprintf("%.3fm/s ,", temp.velocity);
            }
        }

        if (speedconfig.profiles.size())
        {
            model->removeRows(0, model->rowCount());
        }

        for (uint8_t i = 0; i < speedconfig.profiles.size(); i++)
        {
            int row = model->rowCount();
            model->insertRow(row);
            model->setData(model->index(row, 0), row + 1);
            model->setData(model->index(row, 1), speedconfig.profiles.at(i).velocity);
        }

        if (ui->data_check->isChecked())
        {
            framecounter++;
            ui->framecounter->setText(QString("%1\n").arg(framecounter));
        }

        ResultText.setPlainText(str);
        ResultText.setPos(200, 100);

        chart.scene()->removeItem(&ResultText);
        chart.scene()->addItem(&ResultText);
    }

    if (!RangeQueue.empty())
    {
        RangeConfiguartion rangeconfig;
        if (RangeQueue.try_dequeue(rangeconfig))
        {
            if (ui->mult_chk->isChecked())
            {
                for (size_t i = 0; i < rangeconfig.result.size(); i++)
                {
                    str += QString("r%1:").arg(rangeconfig.result.at(i).id) + QString::asprintf("%.3fm ,", rangeconfig.result.at(i).range);
                }
            }
            else {
                if (rangeconfig.result.size())
                {
                    str += QString("r%1:").arg(rangeconfig.result.at(rangeconfig.search_index).id) 
                        + QString::asprintf("%.3fm ,", rangeconfig.result.at(rangeconfig.search_index).range) 
                        + QString::asprintf("%d ,", rangeconfig.index.at(0));
                }
            }

            ResultText.setPlainText(str);
            ResultText.setPos(200, 100);

            if (ui->data_check->isChecked())
            {
                framecounter++;
                ui->framecounter->setText(QString("%1\n").arg(framecounter));
            }

            chart.scene()->removeItem(&ResultText);
            chart.scene()->addItem(&ResultText);

        }
    }

}


void MainWindow::configureDeviceVisualization(int ConfigType)
{

    if (xData.size() < fft_mag_data->size()) {
        xData.resize(fft_mag_data->size());
    }

    // 确定要配置的设备类型
    int targetDeviceType = (ConfigType == DeviceType) ? DeviceType : ConfigType;


    QValueAxis* m_axisX = (QValueAxis*)chart.axes(Qt::Horizontal, &FFTSeries).at(0);
    QValueAxis* m_axisY = (QValueAxis*)chart.axes(Qt::Vertical, &FFTSeries).at(0);

    switch (targetDeviceType) 
    {
    case protocol::DeviceAddress::OBJECT:
        m_axisX->setRange(0, 45);
        m_axisX->setTickCount(30);
        m_axisY->setRange(0, 100);
        chartView->range_update();

        for (size_t i = 0; i < fft_mag_data->size(); ++i) {
            xData[i] = i * objectDistRes;
        }
        break;

    case protocol::DeviceAddress::LIQUID:
        m_axisX->setRange(-21, 21);
        m_axisX->setTickCount(30);
        m_axisY->setRange(0, 100);
        chartView->range_update();

        {
            const size_t halfSize = fft_mag_data->size() / 2;

            for (size_t i = 0; i < halfSize; ++i) {
                xData[i] = (i + 1) * liquidSpeedRes;
            }

            for (size_t i = 0; i < halfSize; ++i) {
                xData[i + halfSize] = -(static_cast<float>(halfSize) - (i + 1)) * liquidSpeedRes;
            }
        }
        break;

    default:
        qDebug() << "unsupported protocol:" << targetDeviceType;
        break;
    }

    // 如果是切换设备类型，更新当前设备类型
    if (ConfigType != DeviceType) 
    {
        DeviceType = ConfigType;
    }
}

void MainWindow::processDeviceData(std::vector<uint16_t>& data)
{
    if (DeviceType == protocol::DeviceAddress::OBJECT)
    {
        processLevelData(data);
    }
    else if (DeviceType == protocol::DeviceAddress::LIQUID)
    {
        processLiquidData(data);
    }

    //// 处理数据记录
    //if (ui->data_check->isChecked())
    //{
    //    obj_data_ready = true;
    //    obj_cv.notify_all();
    //}
}



void MainWindow::processLevelData(std::vector<uint16_t>& data)
{
    calculatedDistance.clear();
    for (const auto& index : FoundPeak.begin()->first)
    {
        uint16_t adjustedIndex = index + 1;     // 0-511 ->  1-512
        if (adjustedIndex >= MaskLength && adjustedIndex <= data.size() - MaskLength)
        {
            calculatedDistance.push_back(static_cast<float>(adjustedIndex));
            break;
        }
        // 计算距离值
        for (size_t i = 0; i < calculatedDistance.size(); ++i)
        {
            calculatedDistance[i] = calculatedDistance[i] * objectDistRes;
        }
    }
}

void MainWindow::processLiquidData(std::vector<uint16_t>& data)
{
    calculatedSpeed.clear();
    const size_t halfSize = data.size() / 2;

    for (const auto& index : FoundPeak.begin()->first)
    {
        uint16_t adjustedIndex = index + 1;
        if ((adjustedIndex >= MaskLength && adjustedIndex <= halfSize) ||
            (adjustedIndex >= halfSize && adjustedIndex <= data.size() - MaskLength))
        {
            calculatedSpeed.push_back(static_cast<float>(adjustedIndex));
        }
    }

    // 计算速度值
    for (size_t i = 0; i < calculatedSpeed.size(); ++i)
    {
        calculatedSpeed[i] = (calculatedSpeed[i] <= halfSize) ?
            (calculatedSpeed[i] * liquidSpeedRes) :
            ((calculatedSpeed[i] - static_cast<float>(data.size())) * liquidSpeedRes);
    }

}
void MainWindow::generateChartData(std::vector<uint16_t>& data, int average)
{
    QList<QPointF> temp, temp1;
    const qreal threshold_value = 20 * log10f(static_cast<float>(average * threshold));

    if (DeviceType == protocol::DeviceAddress::LIQUID)
    {
        generateLiquidChartData(data, temp, temp1, threshold_value);
    }
    else if(DeviceType == protocol::DeviceAddress::OBJECT)
    {
        generateLevelChartData(data, temp, temp1, threshold_value);
    }

    std::unique_lock<std::mutex> lock(mtx);
    point_data.push(temp);
    threshold_data.push(temp1);
}
void MainWindow::generateLiquidChartData(std::vector<uint16_t>& data, QList<QPointF>& a, QList<QPointF>& b, qreal threshold_value)
{
    const size_t halfSize = data.size() / 2;

    // 生成第一部分数据
    for (size_t i = 0; i < halfSize; ++i)
    {
        a << QPointF(xData[i + halfSize],
            20 * log10f(static_cast<float>(data[i + halfSize])));
    }

    // 生成第二部分数据
    for (size_t i = 0; i < halfSize; ++i)
    {
        a << QPointF(xData[i],
            20 * log10f(static_cast<float>(data[i])));
    }

    // 生成阈值线
    for (size_t i = 0; i < data.size(); ++i)
    {
        b << QPointF(xData[i], threshold_value);
    }
}
void MainWindow::generateLevelChartData(std::vector<uint16_t>& data, QList<QPointF>& a, QList<QPointF>& b, qreal threshold_value)
{
    for (size_t i = 0; i < data.size(); ++i)
    {
        a << QPointF(xData[i],
            20 * log10f(static_cast<float>(data[i])));
        b << QPointF(xData[i], threshold_value);
    }
}

void MainWindow::processRadarDataTask()
{
    while(1)
    {
        std::unique_lock<std::mutex> lock(mtx);

        cv.wait(lock, [this](){return data_ready;});

        data_ready = false;


        auto fft_mag_copy = *fft_mag_data;

        lock.unlock();

        //for (int i = 0; i < fft_mag_copy.size(); ++i)
        //{
        //    sum += fft_mag_copy[i];
        //}
        //两种写法

        const int average = std::accumulate(fft_mag_copy.begin(), fft_mag_copy.end(), 0) /
            static_cast<int>(fft_mag_copy.size());


        FoundPeak = Radar_DataProcess::findpeaks(fft_mag_copy, 8, average*threshold);

        processDeviceData(fft_mag_copy);

        // 生成图表数据
        if (point_data.size() < 5)
        {
            generateChartData(fft_mag_copy, average);
        }

    }
}

//speed
// 
//#define MAX_OBJECTS  8
//typedef struct
//{
//    unsigned int objCount;
//    struct
//    {
//        float range;
//        float velocity;
//        float snr;
//        float res;
//    } objects[MAX_OBJECTS];
//    /**/
//    float vel_self;
//}radar_output_t;    /**/
void MainWindow::receiveRadarData(const awr1843_sensor& data)
{
    //qDebug() << "size is:" << ptr->size();

    int ReceiveDeviceType = protocol::DeviceAddress::UNSUPPORTED_ADDR;
    
    if (data.addr == protocol::DeviceAddress::LIQUID)
    {
        ReceiveDeviceType = protocol::DeviceAddress::LIQUID;
    }
    else if (data.addr == protocol::DeviceAddress::OBJECT)
    {
        ReceiveDeviceType = protocol::DeviceAddress::OBJECT;
    }

    auto ptr = data.ptr;

    //判断是否存在，是否为空，是否为偶数。
    if (!ptr || ptr->empty() || ptr->size() % 2 != 0) {
        qDebug() << "Invalid data received: size =" << (ptr ? ptr->size() : 0);
        return;
    }

    const size_t new_size = ptr->size() / 2;

    fft_mag_data->resize(new_size);

    //一种情况是否是之前的展示设备类型，如果不是，进入第一个分支，
    //还有情况就是相同的设备不同的采样点数，如果不一样，进入第二个分支。
    if (ReceiveDeviceType != DeviceType)
    {
        DeviceType = ReceiveDeviceType;
        configureDeviceVisualization(DeviceType);
    }

    const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(ptr->data());
    int remainingBytes = ptr->size();

    if (data.type == protocol::ProcessReturn::FFT_COMPLETE)
    {
        if (record_fft_mag_data_size != fft_mag_data->size())
        {
            record_fft_mag_data_size = fft_mag_data->size();
            configureDeviceVisualization(DeviceType);
        }
        //std::transform(
        //    raw_data, raw_data + new_size * 2,
        //    fft_mag_data->begin(),
        //    [](const uint8_t* ptr) {
        //        return (static_cast<uint16_t>(ptr[1]) << 8) | ptr[0];
        //    }
        //);
        //两种写法

        const uint8_t* raw_data = reinterpret_cast<const uint8_t*>(ptr->data());
        for (size_t i = 0; i < new_size; ++i)
        {
               const uint8_t reg_l = raw_data[i * 2];
               const uint8_t reg_h = raw_data[i * 2 + 1];
               (*fft_mag_data)[i] = ((static_cast<uint16_t>(reg_h) << 8) | reg_l);
        }

        data_ready = true;
        cv.notify_all();

        if (ui->obj_check->isChecked())
        {
            file_data_ready = true;
            file_cv.notify_all();
        }

    }
    else if (data.type == protocol::ProcessReturn::DISTANCE_COMPLETE)
    {
        RangeConfiguartion rangeConfig;
        rangeConfig.clear();

        //index check
        if (remainingBytes < rangeConfig.index.size() * sizeof(uint16_t))
        {
            return;
        }

        memcpy(rangeConfig.index.data(), raw_data, rangeConfig.index.size() * sizeof(uint16_t));
        raw_data += rangeConfig.index.size() * sizeof(uint16_t);
        remainingBytes -= rangeConfig.index.size() * sizeof(uint16_t);
        //gain check
        if (remainingBytes < rangeConfig.gain.size() * sizeof(float))
        {
            return;
        }

        memcpy(rangeConfig.gain.data(), raw_data, rangeConfig.gain.size() * sizeof(float));
        raw_data += rangeConfig.gain.size() * sizeof(float);
        remainingBytes -= rangeConfig.gain.size() * sizeof(float);

        //czt check
        if (remainingBytes < rangeConfig.czt.size() * sizeof(float))
        {
            return;
        }

        memcpy(rangeConfig.czt.data(), raw_data, rangeConfig.czt.size() * sizeof(float));
        raw_data += rangeConfig.czt.size() * sizeof(float);
        remainingBytes -= rangeConfig.czt.size() * sizeof(float);

        while (remainingBytes > 0 && remainingBytes >= sizeof(track1d))
        {
            track1d temp;
            memcpy(&temp, raw_data, sizeof(track1d));
            raw_data += sizeof(track1d);
            remainingBytes -= sizeof(track1d);

            rangeConfig.result.emplace_back(temp);
        }

        std::sort(rangeConfig.result.begin(), rangeConfig.result.end(), comparetrack1d);



        std::vector<float> vec;
        for (const auto& res : rangeConfig.result)
        {
            float r = abs(res.range - rangeConfig.czt[0]);
            vec.emplace_back(r);
        }

        if (vec.size())
        {
            rangeConfig.search_index = 0;
            float min = vec.at(0);
            for (size_t i = 0; i < vec.size(); ++i) 
            {
                if (min > vec.at(i)) {
                    rangeConfig.search_index = i;
                    min = vec.at(i);
                }
            }
        }

        RangeQueue.enqueue(rangeConfig);
        RangeStoreQueue.enqueue(rangeConfig);

        // 处理数据记录
        if (ui->data_check->isChecked())
        {
            obj_data_ready = true;
            obj_cv.notify_all();
        }
    }
    else if(data.type == protocol::ProcessReturn::SPEED_COMPLETE)
    {
        SpeedConfiguration speedConfig;
        speedConfig.clear();

        unsigned int profileCount = 0;
        memcpy(&profileCount, raw_data, sizeof(unsigned int));
        raw_data += sizeof(unsigned int);
        remainingBytes -= sizeof(unsigned int);

        if (profileCount)
        {
            speedConfig.profiles.reserve(profileCount);

            while (profileCount > 0)
            {
                SpeedProfile profile;
                memcpy(&profile.range, raw_data, sizeof(float));
                raw_data += sizeof(float);
                remainingBytes -= sizeof(float);

                memcpy(&profile.velocity, raw_data, sizeof(float));
                raw_data += sizeof(float);
                remainingBytes -= sizeof(float);

                memcpy(&profile.velocity, raw_data, sizeof(float));
                raw_data += sizeof(float);
                remainingBytes -= sizeof(float);

                memcpy(&profile.res, raw_data, sizeof(float));
                raw_data += sizeof(float);
                remainingBytes -= sizeof(float);
                
                speedConfig.profiles.emplace_back(profile);
                profileCount --;

            }

            SpeedQueue.enqueue(speedConfig);
            SpeedStoreQueue.enqueue(speedConfig);

            // 处理数据记录
            if (ui->data_check->isChecked())
            {
                obj_data_ready = true;
                obj_cv.notify_all();
            }
        }
        
    }
    else if (data.type == protocol::ProcessReturn::RAW_COMPLETE)
    {


    }

}


bool comparetrack1d (const MainWindow::track1d& a, const MainWindow::track1d& b)
{
    return a.range < b.range;
}



//#define MAX_OBJECTS  8
//typedef struct
//{
//    unsigned int objCount;
//    struct
//    {
//        float range;
//        float velocity;
//        float snr;
//        float res;
//    } objects[MAX_OBJECTS];
//    /**/
//    float vel_self;
//}radar_output_t;    /**/




//void MainWindow::speed_display(QByteArray* ptr)
//{
//    int count = ptr->size();
//    char* data = ptr->data();
//    float temp;
//
//    speed_temp.clear();
//    speed_gain.clear();
//
//    unsigned int objCount = 0;
//
//    memcpy(&objCount, data, sizeof(unsigned int));
//    data += sizeof(unsigned int);
//    count -= sizeof(unsigned int);
//
//    if (objCount)
//    {
//        while (objCount > 0)
//        {
//            memcpy(&temp, data, sizeof(float));
//            data += sizeof(float);
//            count -= sizeof(float);
//
//            memcpy(&temp, data, sizeof(float));
//            speed_temp.push_back(temp);
//            data += sizeof(float);
//            count -= sizeof(float);
//
//            memcpy(&temp, data, sizeof(float));
//            speed_gain.push_back(temp);
//            data += sizeof(float);
//            count -= sizeof(float);
//
//            memcpy(&temp, data, sizeof(float));
//            data += sizeof(float);
//            count -= sizeof(float);
//
//            objCount--;
//
//        }
//
//        speed_update_flag = true;
//    }
//}

void MainWindow::rawdata_store_param_config(int flag)
{
    //serial.set_store_flag(flag);
}

void MainWindow::data_store_task()
{
    std::vector<uint16_t>* fft_data_ptr = fft_mag_data.get();
    int speed_count = 0;
    int range_count = 0;
    while (1)
    {

        std::unique_lock<std::mutex> lock(file_mtx);
        file_cv.wait(lock, [this]() {return file_data_ready; });
        file_data_ready = false;

        QString filename;
        if(ui->liquid_radio->isChecked())
        {
            filename = QString("%1/speed/%2.bin").arg(timeStampedFolder).arg(speed_count);
            speed_count += 1;
        }
        else if(ui->level_radio->isChecked())
        {
            filename = QString("%1/range/%2.bin").arg(timeStampedFolder).arg(range_count);
            range_count += 1;
        }

        QFile* file = new QFile(filename);
        if (file->open(QFile::WriteOnly | QIODevice::Truncate))
        {

            QDataStream stream(file);
            
            for (uint16_t i = 0; i < fft_data_ptr->size(); i++)
            {
                stream << (*fft_data_ptr)[i];
            }
            file->close();
        }

    }
}

//frame counter
void MainWindow::data_check_datachanged(int state)
{
    if (!state)
    {
        data_filecounter++;
        framecounter = 0;
        ui->framecounter->setText(QString("0"));
        
    }
    else
    {
        currenttime = QDateTime::currentDateTime().toString("MM-dd@hh_mm_ss") + "_";
    }
   
}

void MainWindow::refreshSerialPort()
{
    if (!SerialPort_->isOpen())
    {
        setupSerialPortUI();
    }
}

void MainWindow::obj_store_task()
{
    currenttime = QDateTime::currentDateTime().toString("MM-dd@hh_mm_ss") + "_";
    int mode = 0;
    while (1)
    {
        std::unique_lock<std::mutex> lock(obj_mtx);
        obj_cv.wait(lock, [this]() {return obj_data_ready; });
        obj_data_ready = false;
        
        QString prefix;

        if (ui->prefilename->text() != "")
        {
            mode = 1;
            prefix = "_" + ui->prefilename->text() + "m";
        }
        else
        {
            prefix = "_" + QString("%1").arg(data_filecounter);
        }
        
        QString filename;
        if (DeviceType == protocol::DeviceAddress::LIQUID)
        {
            filename = QString("%1/speed/%2speed_data%3.dat").arg(timeStampedFolder).arg(currenttime).arg(prefix);
        }
        else if(DeviceType == protocol::DeviceAddress::OBJECT)
        {
            filename = QString("%1/range/%2obj_data%3.dat").arg(timeStampedFolder).arg(currenttime).arg(prefix);
        }

        QFile* file = new QFile(filename);
        if (file->open(QFile::WriteOnly | QIODevice::Append | QFile::Text))
        {
            QTextStream  stream(file);

            stream.setCodec("UTF-8");

            QString str = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");

            if (DeviceType == protocol::DeviceAddress::OBJECT)
            {
                RangeConfiguartion rangeconfig;

                while (!RangeStoreQueue.empty())
                {
                    RangeStoreQueue.try_dequeue(rangeconfig);

                    stream << str << " " << "-i\t";
                    for (uint32_t i = 0; i < 8; i++)
                    {
                        stream << QString::asprintf("i%d:%-*d\t", i, 4, rangeconfig.index[i]);
                    }

                    stream << "-g\t";
                    for (uint32_t i = 0; i < 8; i++)
                    {
                        stream << QString::asprintf("g%d:%-*.4f\t", i, 6, rangeconfig.gain[i]);
                    }

                    stream << "-c\t";
                    for (uint32_t i = 0; i < 8; i++)
                    {
                        stream << QString::asprintf("c%i:%-*.4f\t", i, 6, rangeconfig.czt[i]);
                    }
                    stream << "-o\t";
                    for (uint32_t i = 0; i < rangeconfig.result.size(); i++)
                    {
                        stream << QString::asprintf("r%d:%-*.4f\t", rangeconfig.result.at(i).id, 6, rangeconfig.result.at(i).range);
                    }
                    stream << "-p\t";
                    if (rangeconfig.result.size())
                    {
                        stream << QString::asprintf("r%d:%-*.4f\t", rangeconfig.result.at(rangeconfig.search_index).id, 6, rangeconfig.result.at(rangeconfig.search_index).range);
                    }
                    stream << "\n";

                }
            }
            else if (DeviceType == protocol::DeviceAddress::LIQUID)
            {

                SpeedConfiguration speedconfig;
                float zero = 0.0f;


                while (!SpeedStoreQueue.empty())
                {
                    SpeedStoreQueue.try_dequeue(speedconfig);

                    if (speedconfig.profiles.size())
                    {
                        stream << str << " " << "-i\t";

                        for (int i = 0; i < speedconfig.profiles.size(); i++)
                        {
                            stream << QString::asprintf("s%i:%-*.3f\t", i, 4, speedconfig.profiles.at(i).velocity);
                        }
                        for (int i = speedconfig.profiles.size(); i < 8; i++)
                        {
                            stream << QString::asprintf("s%i:%-*.3f\t", i, 4, zero);
                        }
                    }

                    if (speedconfig.profiles.size())
                    {
                        stream << "-g\t";

                        for (int i = 0; i < speedconfig.profiles.size(); i++)
                        {
                            stream << QString::asprintf("g%i:%-*.3f\t", i, 4, speedconfig.profiles.at(i).snr);
                        }

                        for (int i = speedconfig.profiles.size(); i < 8; i++)
                        {
                            stream << QString::asprintf("g%i:%-*.3f\t", i, 4, zero);
                        }
                    }


                    if (speedconfig.profiles.size())
                        stream << "\n";
                }
            }

            file->close();
        }
    }
}

